package javax.core.common.mongo;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

/**
 * 查询器，主要功能用于构造查询条件
 *
 * @author raos
 * @emil 991207823@qq.com
 * @date 2021/8/30 21:22
 */
public final class QueryRule implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * 升序状态码
     */
    public static final int ASC_ORDER = 101;
    /**
     * 降序状态码
     */
    public static final int DESC_ORDER = 102;
    /**
     * like 状态码
     */
    public static final int LIKE = 1;
    /**
     * in 状态码
     */
    public static final int IN = 2;
    /**
     * not in 状态码
     */
    public static final int NOTIN = 3;
    /**
     * between 状态码
     */
    public static final int BETWEEN = 4;
    /**
     * 等于 状态码
     */
    public static final int EQ = 5;
    /**
     * 不等于 状态码
     */
    public static final int NOTEQ = 6;
    /**
     * 大于 状态码
     */
    public static final int GT = 7;
    /**
     * 大于等于 状态码
     */
    public static final int GE = 8;
    /**
     * 小于 状态码
     */
    public static final int LT = 9;
    /**
     * 小于等于 状态码
     */
    public static final int LE = 10;
    /**
     * 是null 状态码
     */
    public static final int ISNULL = 11;
    /**
     * 不是null 状态码
     */
    public static final int ISNOTNULL = 12;
    /**
     * 是空 状态码
     */
    public static final int ISEMPTY = 13;
    /**
     * 不是空 状态码
     */
    public static final int ISNOTEMPTY = 14;
    /**
     * and 状态码
     */
    public static final int AND = 201;
    /**
     * or 状态码
     */
    public static final int OR = 202;
    /**
     * 连接规则列表
     */
    private List<Rule> ruleList = new ArrayList<>();
    /**
     * 查询条件列表
     */
    private List<QueryRule> queryRuleList = new ArrayList<>();
    /**
     * 属性名称
     */
    private String propertyName;

    /**
     * 无参构造
     */
    private QueryRule() { }

    /**
     * 根据属性名有参构造
     * @param propertyName
     */
    private QueryRule(String propertyName) {
        this.propertyName = propertyName;
    }

    /**
     * 获取一个查询器对象
     * @return
     */
    public static QueryRule getInstance() {
        return new QueryRule();
    }

    /**
     * 添加升序规则
     * @param propertyName
     * @return
     */
    public QueryRule addAscOrder(String propertyName) {
        this.ruleList.add(new Rule(ASC_ORDER, propertyName));
        return this;
    }

    /**
     * 添加降序规则
     * @param propertyName
     * @return
     */
    public QueryRule addDescOrder(String propertyName) {
        this.ruleList.add(new Rule(DESC_ORDER, propertyName));
        return this;
    }

    /**
     * 添加字段是null规则
     * @param propertyName
     * @return
     */
    public QueryRule andIsNull(String propertyName) {
        this.ruleList.add(new Rule(ISNULL, propertyName).setAndOr(AND));
        return this;
    }

    /**
     * 添加字段不是null规则
     * @param propertyName
     * @return
     */
    public QueryRule andIsNotNull(String propertyName) {
        this.ruleList.add(new Rule(ISNOTNULL, propertyName).setAndOr(AND));
        return this;
    }

    /**
     * 添加字段是空规则
     * @param propertyName
     * @return
     */
    public QueryRule andIsEmpty(String propertyName) {
        this.ruleList.add(new Rule(ISEMPTY, propertyName).setAndOr(AND));
        return this;
    }

    /**
     * 添加字段不是空规则
     * @param propertyName
     * @return
     */
    public QueryRule andIsNotEmpty(String propertyName) {
        this.ruleList.add(new Rule(ISNOTEMPTY, propertyName).setAndOr(AND));
        return this;
    }

    /**
     * 添加字段像什么规则
     * @param propertyName
     * @return
     */
    public QueryRule andLike(String propertyName, Object value) {
        this.ruleList.add(new Rule(LIKE, propertyName, new Object[] { value }).setAndOr(AND));
        return this;
    }

    /**
     * 添加字段等于规则
     * @param propertyName
     * @param value
     * @return
     */
    public QueryRule andEqual(String propertyName, Object value) {
        this.ruleList.add(new Rule(EQ, propertyName, new Object[] { value }).setAndOr(AND));
        return this;
    }

    /**
     * 添加字段从什么开始规则
     * @param propertyName
     * @param values
     * @return
     */
    public QueryRule andBetween(String propertyName, Object... values) {
        this.ruleList.add(new Rule(BETWEEN, propertyName, values).setAndOr(AND));
        return this;
    }

    /**
     * 添加字段在什么之中规则
     * @param propertyName
     * @param values
     * @return
     */
    public QueryRule andIn(String propertyName, List<Object> values) {
        this.ruleList.add(new Rule(IN, propertyName, new Object[] { values }).setAndOr(AND));
        return this;
    }

    /**
     * 添加字段在什么之中规则
     * @param propertyName
     * @param values
     * @return
     */
    public QueryRule andIn(String propertyName, Object... values) {
        this.ruleList.add(new Rule(IN, propertyName, values).setAndOr(AND));
        return this;
    }

    /**
     * 添加字段不在什么之中规则
     * @param propertyName
     * @param values
     * @return
     */
    public QueryRule andNotIn(String propertyName, List<Object> values) {
        this.ruleList.add(new Rule(NOTIN, propertyName, new Object[] { values }).setAndOr(AND));
        return this;
    }

    /**
     * 添加字段或不在什么之中规则
     * @param propertyName
     * @param values
     * @return
     */
    public QueryRule orNotIn(String propertyName, Object... values) {
        this.ruleList.add(new Rule(NOTIN, propertyName, values).setAndOr(OR));
        return this;
    }

    /**
     * 添加字段不等于规则
     * @param propertyName
     * @param value
     * @return
     */
    public QueryRule andNotEqual(String propertyName, Object value) {
        this.ruleList.add(new Rule(NOTEQ, propertyName, new Object[] { value }).setAndOr(AND));
        return this;
    }

    /**
     * 添加字段大于规则
     * @param propertyName
     * @param value
     * @return
     */
    public QueryRule andGreaterThan(String propertyName, Object value) {
        this.ruleList.add(new Rule(GT, propertyName, new Object[] { value }).setAndOr(AND));
        return this;
    }

    /**
     * 添加字段大于等于规则
     * @param propertyName
     * @param value
     * @return
     */
    public QueryRule andGreaterEqual(String propertyName, Object value) {
        this.ruleList.add(new Rule(GE, propertyName, new Object[] { value }).setAndOr(AND));
        return this;
    }

    /**
     * 添加字段小于规则
     * @param propertyName
     * @param value
     * @return
     */
    public QueryRule andLessThan(String propertyName, Object value) {
        this.ruleList.add(new Rule(LT, propertyName, new Object[] { value }).setAndOr(AND));
        return this;
    }

    /**
     * 添加字段小于等于规则
     * @param propertyName
     * @param value
     * @return
     */
    public QueryRule andLessEqual(String propertyName, Object value) {
        this.ruleList.add(new Rule(LE, propertyName, new Object[] { value }).setAndOr(AND));
        return this;
    }

    /**
     * 添加字段或是null规则
     * @param propertyName
     * @return
     */
    public QueryRule orIsNull(String propertyName) {
        this.ruleList.add(new Rule(ISNULL, propertyName).setAndOr(OR));
        return this;
    }

    /**
     * 添加字段或不是null规则
     * @param propertyName
     * @return
     */
    public QueryRule orIsNotNull(String propertyName) {
        this.ruleList.add(new Rule(ISNOTNULL, propertyName).setAndOr(OR));
        return this;
    }

    /**
     * 添加字段或是空规则
     * @param propertyName
     * @return
     */
    public QueryRule orIsEmpty(String propertyName) {
        this.ruleList.add(new Rule(ISEMPTY, propertyName).setAndOr(OR));
        return this;
    }

    /**
     * 添加字段或不是空规则
     * @param propertyName
     * @return
     */
    public QueryRule orIsNotEmpty(String propertyName) {
        this.ruleList.add(new Rule(ISNOTEMPTY, propertyName).setAndOr(OR));
        return this;
    }

    /**
     * 添加字段或像什么规则
     * @param propertyName
     * @return
     */
    public QueryRule orLike(String propertyName, Object value) {
        this.ruleList.add(new Rule(LIKE, propertyName, new Object[] { value }).setAndOr(OR));
        return this;
    }

    /**
     * 添加字段或等于规则
     * @param propertyName
     * @return
     */
    public QueryRule orEqual(String propertyName, Object value) {
        this.ruleList.add(new Rule(EQ, propertyName, new Object[] { value }).setAndOr(OR));
        return this;
    }

    /**
     * 添加字段或从什么开始规则
     * @param propertyName
     * @return
     */
    public QueryRule orBetween(String propertyName, Object... values) {
        this.ruleList.add(new Rule(BETWEEN, propertyName, values).setAndOr(OR));
        return this;
    }

    /**
     * 添加字段或在什么之中规则
     * @param propertyName
     * @param values
     * @return
     */
    public QueryRule orIn(String propertyName, List<Object> values) {
        this.ruleList.add(new Rule(IN, propertyName, new Object[] { values }).setAndOr(OR));
        return this;
    }

    /**
     * 添加字段或在什么之中规则
     * @param propertyName
     * @param values
     * @return
     */
    public QueryRule orIn(String propertyName, Object... values) {
        this.ruleList.add(new Rule(IN, propertyName, values).setAndOr(OR));
        return this;
    }

    /**
     * 添加字段或不等于规则
     * @param propertyName
     * @param value
     * @return
     */
    public QueryRule orNotEqual(String propertyName, Object value) {
        this.ruleList.add(new Rule(NOTEQ, propertyName, new Object[] { value }).setAndOr(OR));
        return this;
    }

    /**
     * 添加字段或大于规则
     * @param propertyName
     * @param value
     * @return
     */
    public QueryRule orGreaterThan(String propertyName, Object value) {
        this.ruleList.add(new Rule(GT, propertyName, new Object[] { value }).setAndOr(OR));
        return this;
    }

    /**
     * 添加字段或大于等于规则
     * @param propertyName
     * @param value
     * @return
     */
    public QueryRule orGreaterEqual(String propertyName, Object value) {
        this.ruleList.add(new Rule(GE, propertyName, new Object[] { value }).setAndOr(OR));
        return this;
    }

    /**
     * 添加字段或小于规则
     * @param propertyName
     * @param value
     * @return
     */
    public QueryRule orLessThan(String propertyName, Object value) {
        this.ruleList.add(new Rule(LT, propertyName, new Object[] { value }).setAndOr(OR));
        return this;
    }

    /**
     * 添加字段或小于等于规则
     * @param propertyName
     * @param value
     * @return
     */
    public QueryRule orLessEqual(String propertyName, Object value) {
        this.ruleList.add(new Rule(LE, propertyName, new Object[] { value }).setAndOr(OR));
        return this;
    }

    /**
     * 获取连接规则列表
     * @return
     */
    public List<Rule> getRuleList() {
        return this.ruleList;
    }

    /**
     * 获取查询规则列表
     * @return
     */
    public List<QueryRule> getQueryRuleList() {
        return this.queryRuleList;
    }

    /**
     * 获取属性名
     * @return
     */
    public String getPropertyName() {
        return this.propertyName;
    }

    /**
     * 连接规则对象类
     */
    protected class Rule implements Serializable {
        private static final long serialVersionUID = 1L;
        // 规则的类型
        private int type;
        // 属性名
        private String property_name;
        // 数据数组
        private Object[] values;
        // 拼接字段，默认为 and
        private int andOr = AND;

        public Rule(int paramInt, String paramString) {
            this.property_name = paramString;
            this.type = paramInt;
        }

        public Rule(int paramInt, String paramString, Object[] paramArrayOfObject) {
            this.property_name = paramString;
            this.values = paramArrayOfObject;
            this.type = paramInt;
        }

        public Rule setAndOr(int andOr) {
            this.andOr = andOr;
            return this;
        }

        public int getAndOr() {
            return this.andOr;
        }

        public Object[] getValues() {
            return this.values;
        }

        public int getType() {
            return this.type;
        }

        public String getPropertyName() {
            return this.property_name;
        }
    }

}
